package org.chen.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.chen.common.CategoryConstant;
import org.chen.common.exception.ServiceException;
import org.chen.mapper.CategoryMapper;
import org.chen.domain.dto.CategoryDTO;
import org.chen.domain.dto.CategoryQueryDTO;
import org.chen.domain.entity.Category;
import org.chen.domain.vo.CategoryVO;
import org.chen.service.CategoryService;
import org.chen.utils.CategoryTreeUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;

@Service
@Slf4j
@RequiredArgsConstructor
public class CategoryServiceImpl extends ServiceImpl<CategoryMapper, Category> implements CategoryService {
    private final CategoryMapper categoryMapper;

    @Override
    @Cacheable(key = "#type", value = "category")
    public List<CategoryVO> getTreeByType(String type) {
        LambdaQueryWrapper<Category> categoryLambdaQueryWrapper = new LambdaQueryWrapper<Category>()
                .orderByAsc(Category::getSort);
        if (!"".equals(type)) {
            categoryLambdaQueryWrapper.eq(Category::getType, type);
        }
        List<Category> categories = categoryMapper.selectList(
                categoryLambdaQueryWrapper
        );
        return CategoryTreeUtil.buildTree(categories);
    }

    @Override
    public CategoryVO getById(String id) {
        Category category = categoryMapper.selectById(id);
        if (category == null) {
            throw new ServiceException("分类不存在");
        }
        return convertToVO(category);
    }

    private CategoryVO convertToVO(Category category) {
        if (category == null) {
            return null;
        }

        return CategoryVO.builder()
                .id(category.getId())
                .name(category.getName())
                .code(category.getCode())
                .parentId(category.getParentId())
                .level(category.getLevel())
                .path(category.getPath())
                .sort(category.getSort())
                .status(category.getStatus())
                .icon(category.getIcon())
                .description(category.getDescription())
                .type(category.getType())
                .build();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = "category", key = "#dto.type")
    public void add(CategoryDTO dto) {
        // 检查同级分类名称是否重复
        checkNameUnique(dto);

        Category category = new Category();
        BeanUtils.copyProperties(dto, category);

        // 设置层级和路径
        if (dto.getParentId() != null) {
            Category parent = categoryMapper.selectById(dto.getParentId());
            if (parent != null) {
                category.setLevel(parent.getLevel() + 1);
                category.setPath(parent.getPath() + "/" + dto.getName());
            }
        } else {
            category.setLevel(1);
            category.setPath("/" + dto.getName());
        }

        categoryMapper.insert(category);
    }

    private void checkNameUnique(CategoryDTO dto) {
        // 检查同级分类下是否有相同名称
        int count = categoryMapper.countSameNameSiblings(
                dto.getParentId(),
                dto.getName(),
                dto.getId() // 如果是更新操作，需要排除自身
        );

        if (count > 0) {
            throw new ServiceException("同级分类下已存在相同名称的分类");
        }

        // 检查分类层级
        if (dto.getParentId() != null) {
            Category parent = categoryMapper.selectById(dto.getParentId());
            if (parent != null && parent.getLevel() >= CategoryConstant.MAX_LEVEL) {
                throw new ServiceException("最多支持" + CategoryConstant.MAX_LEVEL + "级分类");
            }
        }

        // 检查名称长度
        if (dto.getName().length() > CategoryConstant.MAX_NAME_LENGTH) {
            throw new ServiceException("分类名称长度不能超过" + CategoryConstant.MAX_NAME_LENGTH + "个字符");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = "category", key = "#dto.type")
    public void update(CategoryDTO dto) {
        Category category = categoryMapper.selectById(dto.getId());
        if (category == null) {
            throw new ServiceException("分类不存在");
        }

        // 如果修改了名称，需要更新路径
        if (!category.getName().equals(dto.getName())) {
            updatePathByNameChange(category, dto.getName());
        }

        // 使用UpdateWrapper明确指定要更新的字段
        LambdaUpdateWrapper<Category> updateWrapper = new LambdaUpdateWrapper<Category>()
                .eq(Category::getId, dto.getId())
                .set(Category::getName, dto.getName())
                .set(Category::getCode, dto.getCode())
                .set(Category::getSort, dto.getSort())
                .set(Category::getDescription, dto.getDescription())
                .set(Category::getType, dto.getType())
                .set(Category::getStatus, dto.getStatus())
                .set(Category::getParentId, dto.getParentId());  // 明确设置parentId

        categoryMapper.update(null, updateWrapper);
    }

    private void updatePathByNameChange(Category category, String newName) {
        String oldPath = category.getPath();
        String oldName = category.getName();

        // 更新当前分类的路径
        String newPath = oldPath.substring(0, oldPath.lastIndexOf(oldName)) + newName;
        category.setPath(newPath);

        // 更新所有子分类的路径
        List<Category> children = categoryMapper.selectList(
                new LambdaQueryWrapper<Category>()
                        .likeRight(Category::getPath, oldPath + "/")
        );

        for (Category child : children) {
            String childNewPath = child.getPath().replace(oldPath, newPath);
            categoryMapper.updatePath(child.getId(), childNewPath);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = "category", allEntries = true)
    public void delete(String id) {
        // 检查是否有子分类
        List<Category> children = categoryMapper.selectList(
                new LambdaQueryWrapper<Category>()
                        .eq(Category::getParentId, id)
        );
        if (!children.isEmpty()) {
            throw new ServiceException("存在子分类，无法删除");
        }

        categoryMapper.deleteById(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void move(String id, String targetParentId) {
        Category category = categoryMapper.selectById(id);
        Category oldParent = categoryMapper.selectById(category.getParentId());
        Category newParent = categoryMapper.selectById(targetParentId);

        // 更新移动节点及其子节点的路径和层级
        updateChildrenPath(category, oldParent.getPath(), newParent.getPath());
    }

    @Override
    public List<CategoryVO> getBatchByIds(List<String> ids) {
        return categoryMapper.selectBatchIds(ids).stream().map(this::convertToVO).collect(Collectors.toList());
    }

    private void updateChildrenPath(Category category, String oldParentPath, String newParentPath) {
        // 更新当前节点
        String newPath = category.getPath().replace(oldParentPath, newParentPath);
        category.setPath(newPath);
        category.setLevel(newPath.split("/").length - 1);
        categoryMapper.updateById(category);

        // 更新子节点
        List<Category> children = categoryMapper.selectList(
                new LambdaQueryWrapper<Category>()
                        .likeRight(Category::getPath, category.getPath() + "/")
        );

        for (Category child : children) {
            String childNewPath = child.getPath().replace(oldParentPath, newParentPath);
            child.setPath(childNewPath);
            child.setLevel(childNewPath.split("/").length - 1);
            categoryMapper.updateById(child);
        }
    }

    @Override
    public List<CategoryVO> list(CategoryQueryDTO query) {
        LambdaQueryWrapper<Category> wrapper = new LambdaQueryWrapper<Category>()
                .like(StringUtils.isNotBlank(query.getName()), Category::getName, query.getName())
                .eq(StringUtils.isNotBlank(query.getType()), Category::getType, query.getType())
                .eq(query.getStatus() != null, Category::getStatus, query.getStatus())
                .orderByAsc(Category::getSort);

        return categoryMapper.selectList(wrapper)
                .stream()
                .map(this::convertToVO)
                .collect(Collectors.toList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = "category", allEntries = true)
    public void batchDelete(List<String> ids) {
        // 检查是否包含系统基础分类
        List<Category> categories = categoryMapper.selectBatchIds(ids);
        for (Category category : categories) {
            if (isBaseCategory(category.getCode())) {
                throw new ServiceException("系统基础分类不能删除");
            }

            // 检查是否有子分类
            Long childCount = categoryMapper.selectCount(
                    new LambdaQueryWrapper<Category>()
                            .eq(Category::getParentId, category.getId())
            );
            if (childCount > 0) {
                throw new ServiceException("分类【" + category.getName() + "】存在子分类，无法删除");
            }
        }

        categoryMapper.deleteByIds(ids);
    }

    @Override
    public String getPath(String id) {
        Category category = categoryMapper.selectById(id);
        if (category == null) {
            throw new ServiceException("分类不存在");
        }
        return category.getPath();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = "category", allEntries = true)
    public void updateStatus(String id, Integer status) {
        Category category = categoryMapper.selectById(id);
        if (category == null) {
            throw new ServiceException("分类不存在");
        }

        // 不允许禁用系统基础分类
        if (isBaseCategory(category.getCode()) && status == 0) {
            throw new ServiceException("系统基础分类不能禁用");
        }

        category.setStatus(status);
        categoryMapper.updateById(category);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CacheEvict(value = "category", allEntries = true)
    public void updateSort(String id, Integer sort) {
        Category category = categoryMapper.selectById(id);
        if (category == null) {
            throw new ServiceException("分类不存在");
        }

        category.setSort(sort);
        categoryMapper.updateById(category);
    }

    @Override
    public List<CategoryVO> getChildren(String id) {
        List<Category> children = categoryMapper.selectList(
                new LambdaQueryWrapper<Category>()
                        .eq(Category::getParentId, id)
                        .orderByAsc(Category::getSort)
        );

        return children.stream()
                .map(this::convertToVO)
                .collect(Collectors.toList());
    }

    // 判断是否是系统基础分类
    private boolean isBaseCategory(String code) {
        return "SOCCER_ODD".equals(code) ||
                "FREE_SUPER_TIPS".equals(code) ||
                "ESPN".equals(code) ||
                (code != null && code.startsWith("ESPN_"));
    }
}
